﻿using FunnyArts.JSAdapter.Attri;
using FunnyArts.JSAdapter.Inter;
using FunnyArts.PrettyClient.Core.Utils;
using FunnyArts.PrettyClient.Model;
using FunnyArts.PrettyClient.Services.Contracts;
using FunnyArts.PrettyClient.Settings.Views.Windows;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace FunnyArts.PrettyClient.Services
{
    public class ApplicationHostService : IHostedService
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly IConfiguration _configuration;
        
        public ApplicationHostService(IServiceProvider serviceProvider, IConfiguration configuration)
        {
            // If you want, you can do something with these services at the beginning of loading the application.
            _serviceProvider = serviceProvider;
            _configuration = configuration;
            
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            return HandleActivationAsync();
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        /// <summary>
        /// Creates main window during activation.
        /// </summary>
        private Task HandleActivationAsync()
        {
            if (Application.Current.Windows.OfType<MainWindow>().Any())
            {
                //return Task.CompletedTask;
            }
            if (_configuration.GetSection("SystemSetting") == null || _configuration.GetSection("SystemSetting")["LoginUrl"] == null)
            {
                SettingsWindow settingsWindow = _serviceProvider.GetRequiredService<SettingsWindow>();
                settingsWindow.Show();
                return Task.CompletedTask;
            }
            IWindow mainWindow = _serviceProvider.GetRequiredService<IWindow>();
            //加载接口
            mainWindow.interfaceLoadTask += new Func<Task>(ResolveInterfaceAssembly);
            //加载插件
            mainWindow.pluginLoadTask = ResolvePluginAssembly();
            mainWindow.Loaded += OnMainWindowLoaded;
            mainWindow?.Show();

            return Task.CompletedTask;
        }

        private void OnMainWindowLoaded(object sender, RoutedEventArgs e)
        {
            if (sender is not MainWindow mainWindow)
            {
                return;
            }
        }

        /// <summary>
        /// 加载插件程序集
        /// </summary>
        /// <param name="assemblyLoadContext"></param>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        private async Task<List<PluginJSObject>> ResolvePluginAssembly()
        {
            return await Task.Run(() =>
            {
                LoggerHelper.Info("[插件]加载插件开始........");
                List<PluginJSObject> plugins = new List<PluginJSObject>();
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugin");
                if (!Directory.Exists(path))
                {
                    LoggerHelper.Info("[插件]缺少插件目录");
                    return plugins;
                }
                // 获取目录中所有DLL文件
                string[] dllFiles = Directory.GetFiles(path, "*.dll");
                // 加载每个DLL文件
                foreach (string dllFile in dllFiles)
                {
                    LoggerHelper.Info("[插件]加载插件:" + dllFile);
                    try
                    {
                        // 加载DLL文件
                        Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllFile);
                        if (assembly != null)
                        {
                            var types = assembly.GetTypes().Where(w => w.GetInterface(nameof(IJavaScriptObject)) != null).ToList();
                            foreach (var type in types)
                            {
                                LoggerHelper.Info("[插件]加载插件类型:" + type.FullName);
                                IJavaScriptObject javaSCriptObject = (IJavaScriptObject)assembly.CreateInstance(type.FullName);
                                PluginJSObject pluginJSObject = new PluginJSObject()
                                {
                                    JavaScriptObject = javaSCriptObject,
                                    HostObjectName = type.GetCustomAttribute<JSObjectAttribute>()?.Name ?? type.Name,
                                };
                                plugins.Add(pluginJSObject);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        LoggerHelper.Error("[插件]加载插件异常:" + ex.ToString());
                    }
                }
                LoggerHelper.Info("[插件]加载插件结束........");
                return plugins;
            });
        }

        /// <summary>
        /// 加载接口程序集
        /// </summary>
        /// <param name="assemblyLoadContext"></param>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public Task ResolveInterfaceAssembly()
        {
            return Task.Run(async () =>
            {
                LoggerHelper.Info("[接口]加载接口必要程序开始");
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Interface");
                if (!Directory.Exists(path))
                {
                    LoggerHelper.Info("[接口]缺少接口目录");
                    return;
                }
                // 获取目录中所有DLL文件
                string[] dllFiles = Directory.GetFiles(path, "*.dll");
                // 加载每个DLL文件
                foreach (string dllFile in dllFiles)
                {
                    LoggerHelper.Info("[接口]加载接口必要程序:" + dllFile);
                    try
                    {
                        // 加载DLL文件
                        Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllFile);
                        if (Path.GetFileNameWithoutExtension(dllFile) == "Ewell.Interface.Common")
                        {
                            Type loginInfoType = assembly?.GetType("Ewell.Interface.Common.Model.Common.LoginInfo");
                            Type userType = assembly?.GetType("Ewell.Interface.Common.Model.Common.User");
                            PropertyInfo loginInfoFieldInfo = loginInfoType?.GetProperty("loginUser", BindingFlags.Public | BindingFlags.Static);
                            if (loginInfoFieldInfo != null)
                                loginInfoFieldInfo.SetValue(loginInfoType, JsonConvert.DeserializeObject(JsonConvert.SerializeObject(LoginInfo.loginUser), userType));//设置用户

                            Type logHelperType = assembly?.GetType("Ewell.Interface.Common.Utils.LogHelper");
                            FieldInfo logHelperFieldInfo = logHelperType?.GetField("_logger", BindingFlags.Public | BindingFlags.Static);
                            if (logHelperFieldInfo != null)
                                logHelperFieldInfo.SetValue(logHelperType, LoggerHelper.logger);//设置日志

                            Type proxyConfigType = assembly?.GetType("Ewell.Interface.Common.Model.Config.ProxyConfig");
                            FieldInfo proxyConfigFieldInfo = proxyConfigType?.GetField("his_getway_url", BindingFlags.Public | BindingFlags.Static);
                            if (proxyConfigFieldInfo != null)
                                proxyConfigFieldInfo.SetValue(proxyConfigType, _configuration.GetSection("SystemSetting")["GateWayUrl"]);//设置网关地址

                            Type interfaceCacheType = assembly?.GetType("Ewell.Interface.Common.Cache.InterfaceCache");
                            MethodInfo methodInfo = interfaceCacheType?.GetMethod("LoadAllInterface", BindingFlags.Public | BindingFlags.Static);
                            if (methodInfo != null)
                                await (Task)methodInfo.Invoke(null, new object[] { });
                        }
                    }
                    catch (Exception ex)
                    {
                        LoggerHelper.Error("[接口]加载接口必要程序异常:" + ex.ToString());
                    }
                }
                LoggerHelper.Info("[接口]加载接口必要程序结束");
            });
        }

        
    }
}
